home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / git-4.3 / git-4 / git-4.3.7 / src / gitps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-08  |  23.0 KB  |  945 lines

  1. /* gitps.c -- a process viewer/killer utility. */
  2.  
  3. /* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. /* Written by Tudor Hulubei and Andrei Pitis.  */
  20.  
  21.  
  22. #ifdef HAVE_CONFIG_H
  23. #include <config.h>
  24. #endif
  25.  
  26. #include <stdio.h>
  27.  
  28. #ifdef HAVE_STDLIB_H
  29. #include <stdlib.h>
  30. #else /* !HAVE_STDLIB_H */
  31. #include "ansi_stdlib.h"
  32. #endif /* !HAVE_STDLIB_H */
  33.  
  34. #include <sys/types.h>
  35. #include <ctype.h>
  36. #include <limits.h>
  37. #include "file.h"
  38. #include <fcntl.h>
  39. #include <signal.h>
  40.  
  41. #ifdef HAVE_UNISTD_H
  42. #include <unistd.h>
  43. #endif /* HAVE_UNISTD_H */
  44.  
  45. #include <errno.h>
  46.  
  47. /* Not all systems declare ERRNO in errno.h... and some systems #define it! */
  48. #if !defined (errno)
  49. extern int errno;
  50. #endif /* !errno */
  51.  
  52. #include "stdc.h"
  53. #include "xstring.h"
  54. #include "xmalloc.h"
  55. #include "tty.h"
  56. #include "window.h"
  57. #include "configure.h"
  58. #include "tilde.h"
  59. #include "misc.h"
  60.  
  61.  
  62. int SCREEN_X;
  63. int SCREEN_Y;
  64.  
  65. #define MAX_KEYS        2048
  66. #define MAX_PROCESSES   1024
  67. #define PS_FIELDS         12
  68.  
  69.  
  70. static char *PSFields[PS_FIELDS] =
  71. {
  72.     "TitleForeground",
  73.     "TitleBackground",
  74.     "TitleBrightness",
  75.     "HeaderForeground",
  76.     "HeaderBackground",
  77.     "HeaderBrightness",
  78.     "ScreenForeground",
  79.     "ScreenBackground",
  80.     "ScreenBrightness",
  81.     "StatusForeground",
  82.     "StatusBackground",
  83.     "StatusBrightness"
  84. };
  85.  
  86. #ifdef HAVE_LINUX
  87. static int PSColors[PS_FIELDS] = 
  88. {
  89.     CYAN, BLUE, ON, CYAN, RED, ON, BLACK, CYAN, OFF, CYAN, BLUE, ON
  90. };
  91. #else   /* !HAVE_LINUX */
  92. static int PSColors[PS_FIELDS] = 
  93. {
  94.     BLACK, WHITE, OFF, WHITE, BLACK, ON, WHITE, BLACK, OFF, BLACK, WHITE, OFF
  95. };
  96. #endif  /* !HAVE_LINUX */
  97.  
  98. #define TitleForeground                 PSColors[0]
  99. #define TitleBackground                 PSColors[1]
  100. #define TitleBrightness                 PSColors[2]
  101. #define HeaderForeground                PSColors[3]
  102. #define HeaderBackground                PSColors[4]
  103. #define HeaderBrightness                PSColors[5]
  104. #define ScreenForeground                PSColors[6]
  105. #define ScreenBackground                PSColors[7]
  106. #define ScreenBrightness                PSColors[8]
  107. #define StatusForeground                PSColors[9]
  108. #define StatusBackground                PSColors[10]
  109. #define StatusBrightness                PSColors[11]
  110.  
  111.  
  112.  
  113. #ifdef HAVE_LINUX
  114. int AnsiColorSequences = ON;
  115. #else   /* !HAVE_LINUX */
  116. int AnsiColorSequences = OFF;
  117. #endif  /* !HAVE_LINUX */
  118.  
  119.  
  120. char cSection[]  = "[GITPS-Color]";
  121. char bwSection[] = "[GITPS-Monochrome]";
  122. int  processes;
  123. int  PID_index;
  124. int  signal_type = 11;  /* index of SIGTERM in signals table */
  125.  
  126. pid_t pid;
  127. char *home;
  128. char *program;
  129. char *tty_name;
  130. size_t tty_name_len;
  131. char *header_text;
  132. char *TempDirectory;
  133. int   UseLastScreenChar;
  134. int   StartupScrollStep;
  135. char *stdout_log_name = NULL;
  136. char *stderr_log_name = NULL;
  137. char *ps_vect[MAX_PROCESSES];
  138. char *global_buf = NULL;
  139. int first_on_screen, current_process, scroll_step;
  140. window_t *title_win, *header_win, *screen_win, *status_win;
  141. #ifdef HAVE_GCC
  142. static char title_text[] = " "PRODUCT" "VERSION" - Process Viewer/Killer";
  143. #else
  144. static char title_text[] = " GNU Interactive Tools 4.3.7 - Process Viewer/Killer";
  145. #endif /* !HAVE_GCC */
  146. static char *GitPsModeHelp;
  147. static char no_perm[] = "not owner !";
  148. static char no_proc[] = "no such process ! (REFRESH recommended)";
  149.  
  150.  
  151. struct SIGNAL
  152. {
  153.     char signame[8];
  154.     int  signal;
  155. };
  156.  
  157. static struct SIGNAL signals[] =
  158. {
  159.     { "SIGHUP ", SIGHUP  },     /*  0 */
  160.     { "SIGINT ", SIGINT  },     /*  1 */
  161.     { "SIGQUIT", SIGQUIT },     /*  2 */
  162.     { "SIGILL ", SIGILL  },     /*  3 */
  163.     { "SIGFPE ", SIGFPE  },     /*  4 */
  164.     { "SIGKILL", SIGKILL },     /*  5 */
  165.     { "SIGUSR1", SIGUSR1 },     /*  6 */
  166.     { "SIGSEGV", SIGSEGV },     /*  7 */
  167.     { "SIGUSR2", SIGUSR2 },     /*  8 */
  168.     { "SIGPIPE", SIGPIPE },     /*  9 */
  169.     { "SIGALRM", SIGALRM },     /* 10 */
  170.     { "SIGTERM", SIGTERM },     /* 11 */
  171.     { "SIGCHLD", SIGCHLD },     /* 12 */
  172.     { "SIGCONT", SIGCONT },     /* 13 */
  173.     { "SIGSTOP", SIGSTOP },     /* 14 */
  174.     { "SIGTSTP", SIGTSTP },     /* 15 */
  175.     { "SIGABRT", SIGABRT },     /* 16 */
  176.     { "SIGTRAP", SIGTRAP }      /* 17 */
  177. };
  178.  
  179.  
  180. #define BUILTIN_OPERATIONS              26
  181.  
  182.  
  183. #define BUILTIN_previous_line            0
  184. #define BUILTIN_next_line                1
  185. #define BUILTIN_scroll_down              2
  186. #define BUILTIN_scroll_up                3
  187. #define BUILTIN_beginning_of_list        4
  188. #define BUILTIN_end_of_list              5
  189. #define BUILTIN_next_signal              6
  190. #define BUILTIN_SIGHUP                   7
  191. #define BUILTIN_SIGINT                   8
  192. #define BUILTIN_SIGQUIT                  9
  193. #define BUILTIN_SIGILL                  10
  194. #define BUILTIN_SIGFPE                  11
  195. #define BUILTIN_SIGKILL                 12
  196. #define BUILTIN_SIGUSR1                 13
  197. #define BUILTIN_SIGSEGV                 14
  198. #define BUILTIN_SIGUSR2                 15
  199. #define BUILTIN_SIGPIPE                 16
  200. #define BUILTIN_SIGALRM                 17
  201. #define BUILTIN_SIGTERM                 18
  202. #define BUILTIN_SIGCHLD                 19
  203. #define BUILTIN_SIGCONT                 20
  204. #define BUILTIN_kill_process            21
  205. #define BUILTIN_refresh                 22
  206. #define BUILTIN_exit                    23
  207. #define BUILTIN_hard_refresh            24
  208.  
  209.  
  210. #define MAX_BUILTIN_NAME                20
  211.  
  212. char built_in[BUILTIN_OPERATIONS][MAX_BUILTIN_NAME] =
  213. {
  214.     "previous-line",
  215.     "next-line",
  216.     "scroll-down",
  217.     "scroll-up",
  218.     "beginning-of-list",
  219.     "end-of-list",
  220.     "next-signal",
  221.     "SIGHUP",
  222.     "SIGINT",
  223.     "SIGQUIT",
  224.     "SIGILL",
  225.     "SIGFPE",
  226.     "SIGKILL",
  227.     "SIGUSR1",
  228.     "SIGSEGV",
  229.     "SIGUSR2",
  230.     "SIGPIPE",
  231.     "SIGALRM",
  232.     "SIGTERM",
  233.     "SIGCHLD",
  234.     "SIGCONT",
  235.     "kill-process",
  236.     "refresh",
  237.     "exit",
  238.     "hard-refresh",
  239. };
  240.  
  241.  
  242. void
  243. removelog()
  244. {
  245.     if (stdout_log_name) unlink(stdout_log_name);
  246.     if (stderr_log_name) unlink(stderr_log_name);
  247. }
  248.  
  249.  
  250. void
  251. settitle()
  252. {
  253.     memset(global_buf, ' ', SCREEN_X);
  254.     memcpy(global_buf, title_text, strlen(title_text));
  255.  
  256.     tty_colors(TitleBrightness, TitleForeground, TitleBackground);
  257.  
  258.     window_cursormove_notify(title_win, 0, 0);
  259.     window_write(global_buf, SCREEN_X);
  260. }
  261.  
  262.  
  263. void
  264. setheader()
  265. {
  266.     memset(global_buf, ' ', SCREEN_X);
  267.     memcpy(global_buf, header_text, strlen(header_text));
  268.  
  269.     tty_colors(HeaderBrightness, HeaderForeground, HeaderBackground);
  270.  
  271.     window_cursormove_notify(header_win, 0, 0);
  272.     window_write(global_buf, SCREEN_X);
  273. }
  274.  
  275.  
  276. void
  277. setstatus(what)
  278.    char *what;
  279. {
  280.     memset(global_buf, ' ', SCREEN_X);
  281.  
  282.     if (what)
  283.         memcpy(global_buf, what, strlen(what));
  284.     else
  285.         memcpy(global_buf, GitPsModeHelp, strlen(GitPsModeHelp));
  286.  
  287.     tty_colors(StatusBrightness, StatusForeground, StatusBackground);
  288.  
  289.     window_cursormove_notify(status_win, 0, 0);
  290.     window_write(global_buf, SCREEN_X - (sizeof(signals[0].signame) - 1) - 1);
  291. }
  292.  
  293.  
  294. void
  295. setsignal()
  296. {
  297.     int len = sizeof(signals[0].signame) - 1;
  298.  
  299.     tty_colors(StatusBrightness, StatusForeground, StatusBackground);
  300.  
  301.     window_cursormove_notify(status_win, 0, SCREEN_X - len - 1);
  302.     window_write(signals[signal_type].signame, len);
  303.  
  304.     if (UseLastScreenChar)
  305.         window_putch(' ');
  306. }
  307.  
  308.  
  309. void
  310. free_ps_list()
  311. {
  312.     int i;
  313.  
  314.     for (i = 0; i < MAX_PROCESSES; i++)
  315.         if (ps_vect[i])
  316.         {
  317.             xfree(ps_vect[i]);
  318.             ps_vect[i] = NULL;
  319.         }
  320. }
  321.  
  322.  
  323. char *
  324. read_ps_line(ps_output, line)
  325.     FILE *ps_output;
  326.     char *line;
  327. {
  328.     int c;
  329.     char *ok;
  330.     size_t lastchar;
  331.  
  332.     ok = fgets(line, SCREEN_X + 1, ps_output);
  333.  
  334.     if (line[lastchar = strlen(line) - 1] == '\n')
  335.         line[lastchar] = 0;
  336.     else
  337.         while ((c = fgetc(ps_output)) != '\n' && c != EOF);
  338.  
  339.     return ok;
  340. }
  341.  
  342.  
  343. int
  344. get_PID_index(ps_output)
  345.     FILE *ps_output;
  346. {
  347.     int i;
  348.     char *h = header_text;
  349.  
  350.     if (read_ps_line(ps_output, header_text) == NULL)
  351.         return -1;
  352.  
  353.     if (strstr(header_text, "PID") == NULL)
  354.         return -1;
  355.  
  356.     for (i = 0; ; i++)
  357.     {
  358.         while (isspace(*h))
  359.             h++;
  360.  
  361.         if (memcmp(h, "PID", 3) == 0)
  362.             return i;
  363.  
  364.         while (!isspace(*h))
  365.             h++;
  366.     }
  367. }
  368.  
  369.  
  370. int
  371. kill_process(process_index)
  372.     int process_index;
  373. {
  374.     int i;
  375.     char pidstr[32];
  376.     char *p = ps_vect[process_index];
  377.  
  378.     if (p == NULL)
  379.         return 0;
  380.  
  381.     for (i = 0; i < PID_index; i++)
  382.     {
  383.         while (isspace(*p)) p++;
  384.         if (memcmp(p, "PID", 3) == 0) return i;
  385.         while (!isspace(*p)) p++;
  386.     }
  387.  
  388.     i = 0;
  389.     while (isspace(*p)) p++;
  390.     while (!isspace(*p)) pidstr[i++] = *p++;
  391.     pidstr[i] = 0;
  392.     return !kill(atoi(pidstr), signals[signal_type].signal);
  393. }
  394.  
  395.  
  396. void
  397. build_ps_list(ps_output)
  398.     FILE *ps_output;
  399. {
  400.     int i = 0;
  401.  
  402.     do
  403.         ps_vect[i] = xmalloc(SCREEN_X + 1);
  404.     while (read_ps_line(ps_output, ps_vect[i++]));
  405.  
  406.     xfree(ps_vect[--i]);
  407.     ps_vect[i] = NULL;
  408.     processes = i;
  409. }
  410.  
  411.  
  412. void
  413. update_process(process, update_color)
  414.     int process, update_color;
  415. {
  416.     memset(global_buf, ' ', SCREEN_X);
  417.     memcpy(global_buf, ps_vect[process], strlen(ps_vect[process]));
  418.  
  419.     if (update_color)
  420.     {
  421.         tty_brightness(ScreenBrightness);
  422.  
  423.         if (process == current_process)
  424.         {
  425.             tty_foreground(ScreenBackground);
  426.             tty_background(ScreenForeground);
  427.         }
  428.         else
  429.         {
  430.             tty_foreground(ScreenForeground);
  431.             tty_background(ScreenBackground);
  432.         }
  433.     }
  434.  
  435.     window_cursormove_notify(screen_win, process - first_on_screen, 0);
  436.     window_write(global_buf, SCREEN_X);
  437. }
  438.  
  439.  
  440. void
  441. update_all()
  442. {
  443.     int i;
  444.  
  445.     tty_colors(ScreenBrightness, ScreenForeground, ScreenBackground);
  446.  
  447.     tty_cursor(OFF);
  448.  
  449.     window_cursormove(screen_win, 0, 0);
  450.  
  451.     for (i = first_on_screen;
  452.          i < processes && (i - first_on_screen < SCREEN_Y - 3); i++)
  453.             if (i != current_process)
  454.                 update_process(i, OFF);
  455.             else
  456.                 window_cursormove_notify(screen_win, i - first_on_screen, 0);
  457.  
  458.     update_process(current_process, ON);
  459.  
  460.     tty_colors(ScreenBrightness, ScreenForeground, ScreenBackground);
  461.  
  462.     memset(global_buf, ' ', SCREEN_X);
  463.  
  464.     for (; i - first_on_screen < SCREEN_Y - 3; i++)
  465.     {
  466.         window_cursormove_notify(screen_win, i - first_on_screen, 0);
  467.         window_write(global_buf, SCREEN_X);
  468.     }
  469.  
  470.     window_cursormove(screen_win, current_process-first_on_screen, SCREEN_X-1);
  471.     tty_cursor(ON);
  472. }
  473.  
  474.  
  475. void
  476. clean_up()
  477. {
  478.     tty_exit();
  479.     removelog();
  480. }
  481.  
  482.  
  483. void
  484. fatal(postmsg)
  485.     char *postmsg;
  486. {
  487.     clean_up();
  488.     fprintf(stderr, "%s: fatal error: %s.\n", program, postmsg);
  489.     exit(1);    
  490. }
  491.  
  492.  
  493. int
  494. ps(args)
  495.     char *args;
  496. {
  497.     char *ps_cmd;
  498.     FILE *stdout_log, *stderr_log;
  499.  
  500.     close(1);
  501.     close(2);
  502.     stdout_log = fopen(stdout_log_name, "w");
  503.     stderr_log = fopen(stderr_log_name, "w");
  504.  
  505.     ps_cmd = xmalloc(16 + (args ? strlen(args) : 0) + 1);
  506.  
  507.     if (args)
  508.         sprintf(ps_cmd, "ps %s", args);
  509.     else
  510.         sprintf(ps_cmd, "ps");
  511.  
  512.     if (system(ps_cmd))
  513.     {
  514.         fclose(stderr_log);
  515.         fclose(stdout_log);
  516.         open(tty_name, O_RDWR);
  517.         open(tty_name, O_RDWR);
  518.         fprintf(stderr, "%s: invalid command line.\n", program);
  519.         return 0;
  520.     }
  521.  
  522.     xfree(ps_cmd);
  523.     fclose(stderr_log);
  524.     fclose(stdout_log);
  525.     open(tty_name, O_RDWR);
  526.     open(tty_name, O_RDWR);
  527.     return 1;
  528. }
  529.  
  530.  
  531. RETSIGTYPE
  532. panic(signum)
  533.     int signum;
  534. {
  535.     fatal_signal(signum);
  536. }
  537.  
  538.  
  539. int
  540. read_keys(keys)
  541.     int keys;
  542. {
  543.     char *contents;
  544.     char key_seq[80];
  545.     int i, j, need_convertion;
  546.  
  547.  
  548.     for (i = keys; i < MAX_KEYS; i++)
  549.     {
  550.         configuration_getvarinfo(key_seq, &contents, 1, NO_SEEK);
  551.  
  552.         if (*key_seq == 0)
  553.             break;
  554.  
  555.         if (*key_seq != '^')
  556.         {
  557.             char *key_seq_ptr = tty_get_symbol_key_seq(key_seq);
  558.  
  559.             if (!(need_convertion = key_seq_ptr == NULL))
  560.                 strcpy(key_seq, key_seq_ptr);
  561.         }
  562.         else
  563.             need_convertion = 1;
  564.  
  565.         if (contents == NULL)
  566.             continue;
  567.  
  568.         for (j = 0; j < BUILTIN_OPERATIONS; j++)
  569.             if (strcmp(contents, built_in[j]) == 0)
  570.                 break;
  571.  
  572.         if (j < BUILTIN_OPERATIONS)
  573.         {
  574.             if (!need_convertion || tty_key_convert(key_seq))
  575.                 tty_key_list_insert(key_seq, (void *)(long)j);
  576.         }
  577.         else
  578.             fprintf(stderr, "%s: invalid built-in operation: %s.\n",
  579.                     program, contents);
  580.     }
  581.  
  582.     return i;
  583. }
  584.  
  585.  
  586. int
  587. main(argc, argv)
  588.     int argc;
  589.     char *argv[];
  590. {
  591.     long key;
  592.     tty_key_t *ks;
  593.     FILE *stdout_log;
  594.     int repeat_count;
  595.     char *tmp, *data = NULL;
  596.     int first_time = 1, keys;
  597.     int need_update, need_update_all, old_current_process;
  598.  
  599.  
  600.     program = argv[0];
  601.     pid     = getpid();
  602.  
  603.     home = getenv("HOME");
  604.     if (home == NULL)
  605.         home = ".";
  606.  
  607.     get_tty_name();
  608.     get_login_name();
  609.  
  610.     tty_get_capabilities();
  611.     tty_kbdinit(TTY_FULL_INPUT);
  612.  
  613.     signal(SIGTERM, panic);
  614.     signal(SIGINT , panic);
  615.     signal(SIGQUIT, panic);
  616.     signal(SIGSEGV, panic);
  617.     signal(SIGHUP,  panic);
  618.  
  619.     signal(SIGILL,  SIG_IGN);
  620.     signal(SIGTRAP, SIG_IGN);
  621.     signal(SIGABRT, SIG_IGN);
  622.     signal(SIGUSR1, SIG_IGN);
  623.     signal(SIGUSR2, SIG_IGN);
  624.     signal(SIGTSTP, SIG_IGN);
  625.     signal(SIGCONT, SIG_IGN);
  626.     signal(SIGALRM, SIG_IGN);
  627.     signal(SIGPIPE, SIG_IGN);
  628.     signal(SIGFPE,  SIG_IGN);
  629.  
  630.     common_configuration_init();
  631.     use_section("[GITPS-Keys]");
  632.     keys = read_keys(0);
  633.     configuration_end();
  634.  
  635.     specific_configuration_init();
  636.  
  637.     tty_get_exit_colors();
  638.  
  639.     tty_get_size(&SCREEN_X, &SCREEN_Y);
  640.     tty_startup();
  641.  
  642.     use_section("[Setup]");
  643.  
  644.     configuration_getvarinfo("TempDirectory", &data, 1, DO_SEEK);
  645.     TempDirectory = data ? tilde_expand(data) : "/tmp";
  646.  
  647.     AnsiColorSequences = get_flag_var("AnsiColorSequences", OFF);
  648.  
  649.     UseLastScreenChar  = get_flag_var("UseLastScreenChar", OFF);
  650.  
  651.     StartupScrollStep  = get_int_var("StartupScrollStep", (SCREEN_Y - 3) / 2);
  652.  
  653.     if (StartupScrollStep <= 0 || StartupScrollStep >= (SCREEN_Y - 3) - 1)
  654.         StartupScrollStep = (SCREEN_Y - 3) / 2;
  655.  
  656.     scroll_step = StartupScrollStep;
  657.  
  658.  
  659.     use_section("[GITPS-Setup]");
  660.  
  661.     GitPsModeHelp = get_string_var("GitPsModeHelp", "");
  662.  
  663.  
  664.     use_section(AnsiColorSequences ? cSection : bwSection);
  665.  
  666.     get_colorset_var(PSColors, PSFields, PS_FIELDS);
  667.  
  668.  
  669.     use_section("[GITPS-Keys]");
  670.  
  671.     keys = read_keys(keys);
  672.  
  673.     if (keys == MAX_KEYS)
  674.         fprintf(stderr, "%s: too many key sequences; only %d are allowed.\n",
  675.                 program, MAX_KEYS);
  676.  
  677.     configuration_end();
  678.  
  679. #ifndef HAVE_LONG_FILE_NAMES
  680.     fprintf(stderr, "%s: warning: your system doesn't support long file names.",
  681.             program);
  682. #endif /* !HAVE_LONG_FILE_NAMES */
  683.  
  684.     stdout_log_name = xmalloc(32 + strlen(TempDirectory) + 1);
  685.     stderr_log_name = xmalloc(32 + strlen(TempDirectory) + 1);
  686.     sprintf(stdout_log_name, "%s/gitps.1.%d", TempDirectory, (int)pid);
  687.     sprintf(stderr_log_name, "%s/gitps.2.%d", TempDirectory, (int)pid);
  688.  
  689.     global_buf  = xmalloc(SCREEN_X + 1);
  690.  
  691.     header_text = xmalloc(SCREEN_X + 1);
  692.  
  693.     title_win  = window_init(0, 0,            1,            SCREEN_X);
  694.     header_win = window_init(0, 1,            1,            SCREEN_X);
  695.     screen_win = window_init(0, 2,            SCREEN_Y - 3, SCREEN_X);
  696.     status_win = window_init(0, SCREEN_Y - 1, 1,            SCREEN_X);
  697.  
  698.     tty_set_mode(TTY_NONCANONIC);
  699.  
  700.     first_on_screen = current_process = 0;
  701.  
  702. restart:
  703.  
  704.     if (ps(argc > 1 ? argv[1] : NULL) == 0)
  705.     {
  706.         removelog();
  707.         goto end;
  708.     }
  709.  
  710.     stdout_log = fopen(stdout_log_name, "r");
  711.     removelog();
  712.  
  713.     if ((PID_index = get_PID_index(stdout_log)) == -1)
  714.         goto end;
  715.  
  716.     free_ps_list();
  717.     build_ps_list(stdout_log);
  718.     fclose(stdout_log);
  719.  
  720.     if (first_time)
  721.     {
  722.         tty_colors(ScreenBrightness, ScreenForeground, ScreenBackground);
  723.         tty_clear();
  724.         first_time = 0;
  725.     }
  726.  
  727.     settitle();
  728.     setstatus(NULL);
  729.     setsignal();
  730.     setheader();
  731.  
  732.     current_process = min(current_process, processes - 1);
  733.  
  734.     update_all();
  735.  
  736.     while (1)
  737.     {
  738.         ks  = tty_get_key(&repeat_count);
  739.         key = (long)ks->aux_data;
  740.  
  741.         switch (key)
  742.         {
  743.             case BUILTIN_previous_line:
  744.  
  745.                 need_update_all = need_update = 0;
  746.  
  747.                 while (repeat_count--)
  748.                 {
  749.                     if (current_process != 0)
  750.                         current_process--;
  751.                     else
  752.                         break;
  753.  
  754.                     if (current_process + 1 == first_on_screen)
  755.                     {
  756.                         first_on_screen = max(0, first_on_screen -
  757.                                               scroll_step);
  758.                         need_update_all = 1;
  759.                     }
  760.                     else
  761.                     {
  762.                         if (!need_update)
  763.                             update_process(current_process + 1, ON);
  764.  
  765.                         need_update = 1;
  766.                     }
  767.                 }
  768.  
  769.                 if (need_update_all)
  770.                     update_all();
  771.                 else
  772.                     if (need_update)
  773.                         update_process(current_process, ON);
  774.                 break;
  775.  
  776.             case BUILTIN_next_line:
  777.  
  778.                 need_update_all = need_update = 0;
  779.  
  780.                 while (repeat_count--)
  781.                 {
  782.                     if (current_process < processes - 1)
  783.                         current_process++;
  784.                     else
  785.                         break;
  786.  
  787.                     if (current_process - first_on_screen >= SCREEN_Y - 3)
  788.                     {
  789.                         first_on_screen = min(first_on_screen +
  790.                                               scroll_step,
  791.                                               processes - 1 -
  792.                                               (SCREEN_Y - 3) + 1);
  793.                         need_update_all = 1;
  794.                         continue;
  795.                     }
  796.  
  797.                     if (!need_update)
  798.                         update_process(current_process - 1, ON);
  799.  
  800.                     need_update = 1;
  801.                 }
  802.  
  803.                 if (need_update_all)
  804.                     update_all();
  805.                 else
  806.                     if (need_update)
  807.                         update_process(current_process, ON);
  808.                 break;
  809.  
  810.             case BUILTIN_scroll_down:
  811.  
  812.                 if (current_process == 0)
  813.                     break;
  814.  
  815.                 old_current_process = current_process;
  816.  
  817.                 if (current_process < SCREEN_Y - 3)
  818.                     current_process = first_on_screen = 0;
  819.                 else
  820.                 {
  821.                     current_process -= SCREEN_Y - 3;
  822.                     first_on_screen = max(0, first_on_screen - (SCREEN_Y - 3));
  823.                 }
  824.  
  825.                 if (processes > SCREEN_Y - 3)
  826.                     update_all();
  827.                 else
  828.                 {
  829.                     update_process(old_current_process, ON);
  830.                     update_process(current_process, ON);
  831.                 }
  832.  
  833.                 break;
  834.  
  835.             case BUILTIN_scroll_up:
  836.  
  837.                 if (current_process == processes - 1)
  838.                     break;
  839.  
  840.                 old_current_process = current_process;
  841.  
  842.                 if (processes - 1 - first_on_screen < SCREEN_Y - 3)
  843.                     current_process = processes - 1;
  844.                 else
  845.                     if (processes - 1 - current_process < SCREEN_Y - 3)
  846.                     {
  847.                         current_process = processes - 1;
  848.                         first_on_screen = processes - 1 - (SCREEN_Y - 3) + 1;
  849.                     }
  850.                     else
  851.                     {
  852.                         current_process += SCREEN_Y - 3;
  853.                         first_on_screen = min(first_on_screen + SCREEN_Y - 3,
  854.                                               (processes - 1) -
  855.                                               (SCREEN_Y - 3) + 1);
  856.                     }
  857.  
  858.                 if (processes > SCREEN_Y - 3)
  859.                     update_all();
  860.                 else
  861.                 {
  862.                     update_process(old_current_process, ON);
  863.                     update_process(current_process, ON);
  864.                 }
  865.  
  866.                 break;
  867.  
  868.             case BUILTIN_beginning_of_list:
  869.  
  870.                 if (current_process == 0)
  871.                     break;
  872.  
  873.                 current_process = first_on_screen = 0;
  874.                 update_all();
  875.                 break;
  876.  
  877.             case BUILTIN_end_of_list:
  878.  
  879.                 if (current_process == processes - 1)
  880.                     break;
  881.  
  882.                 current_process = processes - 1;
  883.                 first_on_screen = max(0, (processes - 1) - (SCREEN_Y - 3) + 1);
  884.                 update_all();
  885.                 break;
  886.  
  887.             case BUILTIN_next_signal:
  888.  
  889.                 signal_type++;
  890.                 signal_type %= sizeof(signals) / sizeof(struct SIGNAL);
  891.                 setsignal();
  892.                 break;
  893.  
  894.             case BUILTIN_SIGHUP : signal_type =  0; setsignal(); break;
  895.             case BUILTIN_SIGINT : signal_type =  1; setsignal(); break;
  896.             case BUILTIN_SIGQUIT: signal_type =  2; setsignal(); break;
  897.             case BUILTIN_SIGILL : signal_type =  3; setsignal(); break;
  898.             case BUILTIN_SIGFPE : signal_type =  4; setsignal(); break;
  899.             case BUILTIN_SIGKILL: signal_type =  5; setsignal(); break;
  900.             case BUILTIN_SIGUSR1: signal_type =  6; setsignal(); break;
  901.             case BUILTIN_SIGSEGV: signal_type =  7; setsignal(); break;
  902.             case BUILTIN_SIGUSR2: signal_type =  8; setsignal(); break;
  903.             case BUILTIN_SIGPIPE: signal_type =  9; setsignal(); break;
  904.             case BUILTIN_SIGALRM: signal_type = 10; setsignal(); break;
  905.             case BUILTIN_SIGTERM: signal_type = 11; setsignal(); break;
  906.             case BUILTIN_SIGCHLD: signal_type = 12; setsignal(); break;
  907.             case BUILTIN_SIGCONT: signal_type = 13; setsignal(); break;
  908.  
  909.             case BUILTIN_hard_refresh:
  910.  
  911.                 first_time = 1;
  912.  
  913.             case BUILTIN_refresh:
  914.  
  915.                 goto restart;
  916.  
  917.             case BUILTIN_exit:
  918.  
  919.                 goto end;
  920.  
  921.             case BUILTIN_kill_process:
  922.  
  923.                 if (!kill_process(current_process))
  924.                 {
  925.                     tty_beep();
  926.                     memset(global_buf, ' ', SCREEN_X);
  927.                     tmp = xmalloc(16 + strlen((errno==EPERM)?no_perm:no_proc));
  928.                     sprintf(tmp, "Error: %s", (errno==EPERM)?no_perm:no_proc);
  929.                     setstatus(tmp);
  930.                     xfree(tmp);
  931.                     errno = 0;
  932.                     tty_get_key(NULL);
  933.                     setstatus(NULL);
  934.                     setsignal();
  935.                 }
  936.                 break;
  937.         }
  938.     }
  939.  
  940.   end:
  941.  
  942.     clean_up();
  943.     return 0;
  944. }
  945.